﻿using Garnet.client;
using StackExchange.Redis;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace GarnetClientSample
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            await TestGarnetClient();
            await TestGarnetWithStackExchangeRedis();
            Console.ReadKey();
        }

        /// <summary>
        /// GarnetClient 目前不支持切换数据库
        /// </summary>
        /// <returns></returns>
        static async Task TestGarnetClient()
        {
            var manager = new GarnetDbManager("127.0.0.1", 6379);
            try
            {
                // 连接到服务器
                manager.Connect();

                Console.WriteLine("===GarnetClient 基本读写操作 ===\n");

                // 写入数据
                await manager.SetAsync("user:1", "Alice");
                await manager.SetAsync("user:2", "Bob");

                // 读取数据
                var user1 = await manager.GetAsync("user:1");
                var user2 = await manager.GetAsync("user:2");

                Console.WriteLine("\n=== 使用键前缀来组织数据（代替多数据库） ===\n");

                // 由于 Garnet 不支持多数据库，建议使用键前缀来组织数据
                // 例如：使用 "db0:" 和 "db1:" 前缀来模拟不同的数据库
                await manager.SetAsync("db0:user:1", "Alice");
                await manager.SetAsync("db0:user:2", "Bob");
                await manager.SetAsync("db1:product:1", "Laptop");
                await manager.SetAsync("db1:product:2", "Phone");

                // 读取不同"数据库"的数据
                var db0User = await manager.GetAsync("db0:user:1");
                var db1Product = await manager.GetAsync("db1:product:1");

                Console.WriteLine("\n=== 批量操作 ===\n");

                // 批量写入
                await manager.SetMultipleAsync(
                    ("batch:1", "value1"),
                    ("batch:2", "value2"),
                    ("batch:3", "value3")
                );

                // 批量读取
                var values = await manager.GetMultipleAsync("batch:1", "batch:2", "batch:3");

                Console.WriteLine("\n=== 过期时间操作 ===\n");

                // 设置带过期时间的键
                await manager.SetWithExpiryAsync("temp:session", "xyz123", TimeSpan.FromSeconds(60));

                Console.WriteLine("\n=== 键操作 ===\n");

                // 检查键是否存在
                await manager.ExistsAsync("user:1");
                await manager.ExistsAsync("nonexistent:key");

                // 获取所有匹配的键
                await manager.GetKeysAsync("db0:*");
                await manager.GetKeysAsync("db1:*");

                Console.WriteLine("\n=== 删除操作 ===\n");

                // 单个删除
                await manager.DeleteAsync("user:2");
                await manager.GetAsync("user:2"); // 应该返回 null

                // 批量删除
                await manager.DeleteMultipleAsync("batch:1", "batch:2", "batch:3");

                Console.WriteLine("\n=== 提示 ===");
                Console.WriteLine("Garnet 目前不支持 SELECT 命令切换数据库");
                Console.WriteLine("建议使用键前缀来组织数据，例如：");
                Console.WriteLine("  - db0:user:1, db0:user:2 (模拟数据库0)");
                Console.WriteLine("  - db1:product:1, db1:product:2 (模拟数据库1)");
                Console.WriteLine("  - app1:*, app2:* (按应用分组)");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
            }
            finally
            {
                manager.Disconnect();
            }
            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }

        /// <summary>
        /// StackExchangeRedis操作Garnet,支持切换数据库
        /// </summary>
        /// <returns></returns>
        static async Task TestGarnetWithStackExchangeRedis()
        {
            try
            {

                // 连接到 Garnet 服务器
                var connection = await ConnectionMultiplexer.ConnectAsync("localhost:6379");
                var db = connection.GetDatabase();
                var db1 = connection.GetDatabase(1);
                await db1.StringSetAsync("mykey", "Hello Garnet!");
                Console.WriteLine("\n=== StackExchangeRedis基本字符串操作 ===");

                // 写入字符串
                await db.StringSetAsync("mykey", "Hello Garnet!");
                Console.WriteLine("写入: mykey = 'Hello Garnet!'");

                // 读取字符串
                var value = await db.StringGetAsync("mykey");
                Console.WriteLine($"读取: mykey = '{value}'");

                // 带过期时间的写入
                await db.StringSetAsync("temp_key", "This will expire", TimeSpan.FromSeconds(10));
                Console.WriteLine("写入带过期时间的键: temp_key (10秒后过期)");

                Console.WriteLine("\n=== 哈希表操作 ===");

                // 哈希表操作
                var hashKey = "user:1001";
                await db.HashSetAsync(hashKey,
                    new HashEntry[]
                    {
            new("name", "张三"),
            new("age", 30),
            new("email", "zhangsan@example.com")
                    });
                Console.WriteLine($"创建哈希: {hashKey}");

                // 读取哈希字段
                var userName = await db.HashGetAsync(hashKey, "name");
                var userAge = await db.HashGetAsync(hashKey, "age");
                Console.WriteLine($"读取哈希: name={userName}, age={userAge}");

                // 获取所有哈希字段
                var allFields = await db.HashGetAllAsync(hashKey);
                Console.WriteLine("所有字段:");
                foreach (var field in allFields)
                {
                    Console.WriteLine($"  {field.Name}: {field.Value}");
                }

                Console.WriteLine("\n=== 列表操作 ===");

                // 列表操作
                var listKey = "messages";
                await db.ListRightPushAsync(listKey, "消息1");
                await db.ListRightPushAsync(listKey, "消息2");
                await db.ListRightPushAsync(listKey, "消息3");
                Console.WriteLine("向列表添加3个消息");

                // 读取列表范围
                var messages = await db.ListRangeAsync(listKey);
                Console.WriteLine("列表内容:");
                for (int i = 0; i < messages.Length; i++)
                {
                    Console.WriteLine($"  [{i}] {messages[i]}");
                }

                // 弹出列表元素
                var firstMessage = await db.ListLeftPopAsync(listKey);
                Console.WriteLine($"弹出第一个消息: {firstMessage}");

                Console.WriteLine("\n=== 集合操作 ===");

                // 集合操作
                var setKey = "tags";
                await db.SetAddAsync(setKey, "tech");
                await db.SetAddAsync(setKey, "programming");
                await db.SetAddAsync(setKey, "dotnet");
                Console.WriteLine("向集合添加标签");

                // 检查集合成员
                var isTechTag = await db.SetContainsAsync(setKey, "tech");
                Console.WriteLine($"集合包含 'tech': {isTechTag}");

                // 获取所有集合成员
                var allTags = await db.SetMembersAsync(setKey);
                Console.WriteLine("所有标签: " + string.Join(", ", allTags));

                Console.WriteLine("\n=== 有序集合操作 ===");

                // 有序集合操作
                var sortedSetKey = "leaderboard";
                await db.SortedSetAddAsync(sortedSetKey, "玩家A", 100);
                await db.SortedSetAddAsync(sortedSetKey, "玩家B", 200);
                await db.SortedSetAddAsync(sortedSetKey, "玩家C", 150);
                Console.WriteLine("创建排行榜");

                // 获取排名
                var topPlayers = await db.SortedSetRangeByRankWithScoresAsync(sortedSetKey, 0, 2, Order.Descending);
                Console.WriteLine("排行榜前三:");
                foreach (var player in topPlayers)
                {
                    Console.WriteLine($"  {player.Element}: {player.Score}分");
                }

                Console.WriteLine("\n=== 对象序列化操作 ===");

                // 复杂对象存储示例
                var user = new User { Id = 1, Name = "李四", Email = "lisi@example.com", CreatedAt = DateTime.Now };
                var userJson = JsonSerializer.Serialize(user);
                await db.StringSetAsync($"user:{user.Id}", userJson);
                Console.WriteLine($"存储用户对象: {user.Name}");

                // 读取并反序列化对象
                var userJsonFromDb = await db.StringGetAsync($"user:{user.Id}");
                var userFromDb = JsonSerializer.Deserialize<User>(userJsonFromDb);
                Console.WriteLine($"读取用户对象: {userFromDb.Name} ({userFromDb.Email})");

                Console.WriteLine("\n=== 批量操作 ===");

                // 批量操作
                var batch = db.CreateBatch();
                var tasks = new List<Task>();

                for (int i = 1; i <= 5; i++)
                {
                    tasks.Add(batch.StringSetAsync($"batch_key_{i}", $"value_{i}"));
                }

                batch.Execute();
                await Task.WhenAll(tasks);
                Console.WriteLine("批量写入5个键");

                // 批量读取
                var values = await db.StringGetAsync(new RedisKey[] { "batch_key_1", "batch_key_3", "batch_key_5" });
                Console.WriteLine("批量读取结果:");
                for (int i = 0; i < values.Length; i++)
                {
                    Console.WriteLine($"  Key {i + 1}: {values[i]}");
                }

                Console.WriteLine("\n=== 键操作 ===");

                // 键搜索
                var keys = connection.GetServer("localhost:6379").Keys(pattern: "batch_key_*").ToArray();
                Console.WriteLine($"找到 {keys.Length} 个匹配 'batch_key_*' 的键");

                // 删除键
                await db.KeyDeleteAsync("mykey");
                Console.WriteLine("删除键 'mykey'");

                // 检查键是否存在
                var exists = await db.KeyExistsAsync("mykey");
                Console.WriteLine($"键 'mykey' 是否存在: {exists}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"异常: {ex.ToString()}");
            }
        }
    }
}
